import SwiftUI
import SQLite3
class TimerHolder: ObservableObject {
    @Published var timer: Timer?
}
struct AutoEncryptionView: View {
    let user: User?

    @State private var watchDirectory: URL?
    @State private var outputDirectory: URL?
    @State private var watchDirectoryScopedAccess: Bool = false
    @State private var outputDirectoryScopedAccess: Bool = false
    @State private var isWatching: Bool = false
    
    @State private var isProcessing: Bool = false
    @State private var fileStabilityMap: [String: (size: Int64, timestamp: Date)] = [:]
    
    @State private var files: [FileItem] = []
    @State private var showingWatchDirectoryPicker = false
    @State private var showingOutputDirectoryPicker = false
    @State private var Rights: [Right] = []
    @State private var selectedRight: Right? = nil
    @State private var isLoadingRights = false
    @State private var selectedFileID: UUID? = nil
    @State private var shouldStopEncryption: Bool = false
    @State private var currentProcessingFileID: UUID? = nil
    @StateObject private var timerHolder = TimerHolder()

    struct Right: Identifiable, Hashable {
        let id: String
        let name: String
    }

    // 添加窗口代理属性
    @State private var windowDelegate: WindowDelegate? = nil
    private var serviceURL: String {
        user?.isChineseVersion ?? false ? "https://4.drm-x.cn/haihaisoftlicenseservice.asmx" : "https://4.drm-x.com/haihaisoftlicenseservice.asmx"
    }

    private let databasePath = FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent("FileProcessLogDB.db").path

    // MARK: 界面布局入口
    var body: some View {
        let isChinese = user?.isChineseVersion ?? false
        VStack(spacing: 16) {
            HStack {
                Text(localized("scan_directory", isChinese: isChinese)).frame(width: 110, alignment: .leading)
                TextField(localized("set_scan_directory", isChinese: isChinese), text: Binding(get: { watchDirectory?.path ?? "" }, set: { _ in })).disabled(true)
                Button(localized("browse", isChinese: isChinese)) {
                    showingWatchDirectoryPicker = true
                }
                .fileImporter(isPresented: $showingWatchDirectoryPicker, allowedContentTypes: [.folder], allowsMultipleSelection: false) { result in
                    if case .success(let urls) = result, let url = urls.first {
                        watchDirectory?.stopAccessingSecurityScopedResource()
                        watchDirectory = url
                    }
                }
            }

            HStack {
                Text(localized("output_directory", isChinese: isChinese)).frame(width: 110, alignment: .leading)
                TextField(localized("select_output_directory", isChinese: isChinese), text: Binding(get: { outputDirectory?.path ?? "" }, set: { _ in })).disabled(true)
                Button(localized("browse", isChinese: isChinese)) {
                    showingOutputDirectoryPicker = true
                }
                // 修改文件选择器代码
                .fileImporter(isPresented: $showingOutputDirectoryPicker, allowedContentTypes: [.folder], allowsMultipleSelection: false) { result in
                    if case .success(let urls) = result, let url = urls.first {
                        outputDirectory?.stopAccessingSecurityScopedResource()
                        outputDirectory = url
                        outputDirectoryScopedAccess = url.startAccessingSecurityScopedResource()
                    }
                }
            }
            
            //MARK: 许可证权限选择
            HStack {
                Text(localized("license_right", isChinese: isChinese))
                    .frame(width: 110, alignment: .leading)
                
                if isLoadingRights {
                    ProgressView()
                } else {
                    Picker("", selection: $selectedRight) {
                        ForEach(Rights, id: \.self) { right in
                            Text("\(right.id) || \(right.name)").tag(right as Right?)
                        }
                    }
                    .frame(maxWidth: .infinity, alignment: .leading)
                    .onChange(of: selectedRight) { newValue in }
                }
            }

            // MARK: 文件列表
            ScrollViewReader { proxy in
                List(selection: $selectedFileID) {
                    HStack {
                        Text(localized("file_name", isChinese: isChinese)).font(.headline).frame(width: 200, alignment: .leading)
                        Text(localized("input_path", isChinese: isChinese)).font(.headline).frame(width: 180, alignment: .leading)
                        Text(localized("output_path", isChinese: isChinese)).font(.headline).frame(width: 180, alignment: .leading)
                        Text(localized("file_size", isChinese: isChinese)).font(.headline).frame(width: 80, alignment: .leading)
                        Text(localized("status", isChinese: isChinese)).font(.headline).frame(width: 140, alignment: .leading)
                    }
                    .padding(.vertical, 4)
                    ForEach(files) { file in
                        HStack {
                            Text(file.name).frame(width: 200, alignment: .leading).lineLimit(1).help(file.name)
                            Text(file.inputPath).frame(width: 180, alignment: .leading).lineLimit(1).help(file.inputPath)
                            Text(file.outputPath.isEmpty ? "..." : file.outputPath).frame(width: 180, alignment: .leading).foregroundColor(file.outputPath.isEmpty ? .gray : .primary).lineLimit(1).help(file.outputPath.isEmpty ? "..." : file.outputPath)
                            Text(file.formattedSize).frame(width: 80, alignment: .leading)
                            Text(file.status.localizedString(isChinese: user?.isChineseVersion ?? false)).frame(width: 140, alignment: .leading).foregroundColor(statusColor(for: file.status))
                        }
                        .padding(.vertical, 2)
                        .tag(file.id)
                        .id(file.id)
                        .contentShape(Rectangle()) // 让整行都可以被点击
                        .onTapGesture {
                            selectedFileID = file.id
                        }
                        .simultaneousGesture(
                            TapGesture(count: 2).onEnded { // 双击打开
                                selectedFileID = file.id
                                openFile(url: URL(fileURLWithPath: file.inputPath))
                            }
                        )
                        .contextMenu {
                            Button(localized("open_input_folder", isChinese: isChinese)) {
                                selectedFileID = file.id
                                openFolder(url: URL(fileURLWithPath: file.inputPath))
                            }
                            Button(localized("open_output_folder", isChinese: isChinese)) {
                                selectedFileID = file.id
                                if !file.outputPath.isEmpty {
                                    openFolder(url: URL(fileURLWithPath: file.outputPath))
                                }
                            }
                        }
                        .background(
                            selectedFileID == file.id ? Color.blue.opacity(0.2) : Color.clear
                        )
                    }
                }
                .frame(maxHeight: .infinity)
                .listStyle(PlainListStyle())
                .onChange(of: currentProcessingFileID) { newValue in
                    if let id = newValue {
                        withAnimation {
                            proxy.scrollTo(id, anchor: .center)
                        }
                    }
                }
            }

            // MARK: 界面按钮
            HStack {
                Button(action: startScanning) {
                    Text(isWatching ? localized("scanning", isChinese: isChinese) : localized("start_scanning", isChinese: isChinese)).frame(width: 100, height: 30)
                }
                .disabled(isWatching || watchDirectory == nil || outputDirectory == nil)
                .buttonStyle(.borderedProminent)

                Button(action: stopScanning) {
                    Text(localized("stop_scanning", isChinese: isChinese)).frame(width: 100, height: 30)
                }
                .disabled(!isWatching)
                .buttonStyle(.bordered)

                Button(action: clearFiles) {
                    Text(localized("clear_list", isChinese: isChinese)).frame(width: 100, height: 30)
                }
                .disabled(isWatching)
                .buttonStyle(.bordered)
            }
            .padding(.top, 8)
        }
        .padding()
        
        // 在 onAppear 中设置窗口代理
        .onAppear {
            createLogDatabaseIfNeeded()
            loadRights()
            // 设置窗口代理
            DispatchQueue.main.async {
                if let window = NSApplication.shared.windows.first(where: { $0.isKeyWindow }) {
                    let isChinese = user?.isChineseVersion ?? false
                    self.windowDelegate = WindowDelegate(
                        isProcessing: isWatching, 
                        isChinese: isChinese,
                        taskType: .autoScanning,
                        onWindowClose: {
                            // 设置停止标志
                            self.shouldStopEncryption = true
                            self.isWatching = false
                            self.timerHolder.timer?.invalidate()
                            self.timerHolder.timer = nil
                            
                            // 等待当前任务完成
                            DispatchQueue.global(qos: .background).async {
                                // 等待当前处理完成
                                while self.isProcessing {
                                    Thread.sleep(forTimeInterval: 0.1)
                                }
                            }
                        }
                    )
                    window.delegate = self.windowDelegate
                    
                    // 监听 isWatching 状态变化
                    NotificationCenter.default.addObserver(forName: NSNotification.Name("WatchingStatusChanged"), object: nil, queue: .main) { notification in
                        if let isWatching = notification.userInfo?["isWatching"] as? Bool {
                            self.windowDelegate = WindowDelegate(
                                isProcessing: isWatching, 
                                isChinese: isChinese,
                                taskType: .autoScanning,
                                onWindowClose: {
                                    // 设置停止标志
                                    self.shouldStopEncryption = true
                                    self.isWatching = false
                                    self.timerHolder.timer?.invalidate()
                                    self.timerHolder.timer = nil
                                    
                                    // 等待当前任务完成
                                    DispatchQueue.global(qos: .background).async {
                                        // 等待当前处理完成
                                        while self.isProcessing {
                                            Thread.sleep(forTimeInterval: 0.1)
                                        }
                                    }
                                }
                            )
                            window.delegate = self.windowDelegate
                        }
                    }
                }
            }
        }
    }
    // 在 isWatching 变化时发送通知
    private func updateWatchingStatus() {
        NotificationCenter.default.post(
            name: NSNotification.Name("WatchingStatusChanged"),
            object: nil,
            userInfo: ["isWatching": isWatching]
        )
    }
    
    // 加载权限列表
    private func loadRights() {
        guard let user = user else { return }
        
        isLoadingRights = true
        
        let client = SOAPClient()
        client.listRights(
            endpoint: serviceURL,
            soapAction: serviceURL + "?op=ListRightsAsString",
            adminemail: user.adminemail,
            authStr: user.webServiceCode
        ) { result in
            DispatchQueue.main.async {
                isLoadingRights = false
                if let result = result {
                    // 解析权限字符串，格式应该是 "ID,名称;ID,名称;..."
                    let rightsList = result.components(separatedBy: ";;")
                        .map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
                        .filter { !$0.isEmpty }
                    
                    // 将每个权限字符串解析为 ID 和名称
                    self.Rights = rightsList.compactMap { rightStr -> Right? in
                        let parts = rightStr.components(separatedBy: "||")
                        if parts.count >= 2 {
                            return Right(id: parts[0], name: parts[1])
                        }
                        return nil
                    }
                    
                    // 如果有权限，默认选择第一个
                    if !self.Rights.isEmpty {
                        self.selectedRight = self.Rights[0]
                        //print("已选择权限: ID=\(self.selectedRight!.id), 名称=\(self.selectedRight!.name)")
                    }
                } else {
                    print("获取权限列表失败")
                }
            }
        }
    }

    // MARK: 开始扫描
    private func startScanning() {
        isWatching = true
        shouldStopEncryption = false  // 重置停止标志
        updateWatchingStatus()

        // 在后台线程执行扫描和加密操作
        DispatchQueue.global(qos: .userInitiated).async {
            self.scanAndUpdateFiles()
        }
        
        timerHolder.timer = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: true) { _ in
            if self.isWatching {
                // 在后台线程执行扫描和加密操作
                DispatchQueue.global(qos: .userInitiated).async {
                    self.scanAndUpdateFiles()
                }
            }
        }
    }

    // MARK: 停止扫描
    private func stopScanning() {
        let isChinese = user?.isChineseVersion ?? false
        
        // 创建确认对话框
        let alert = NSAlert()
        alert.messageText = localized("stop_scanning_confirmation_title", isChinese: isChinese)
        alert.informativeText = localized("stop_scanning_confirmation_message", isChinese: isChinese)
        alert.alertStyle = .warning
        alert.addButton(withTitle: localized("confirm", isChinese: isChinese))
        alert.addButton(withTitle: localized("cancel", isChinese: isChinese))
        
        let response = alert.runModal()
        
        if response == .alertFirstButtonReturn {
            // 用户确认停止
            isWatching = false
            shouldStopEncryption = true  // 设置停止标志
            timerHolder.timer?.invalidate()
            timerHolder.timer = nil
            
            // 显示停止提示
            DispatchQueue.main.async {
                let alert = NSAlert()
                alert.messageText = localized("scan_stopped_title", isChinese: isChinese)
                alert.informativeText = localized("scan_stopped_message", isChinese: isChinese)
                alert.alertStyle = .informational
                alert.addButton(withTitle: localized("ok", isChinese: isChinese))
                alert.runModal()
            }
        }
        // 如果用户取消，则不执行任何操作
    }

    // MARK: 清除列表
    private func clearFiles() {
        files.removeAll()
    }

    // MARK: 扫描并更新文件列表
    
    private func scanAndUpdateFiles() {
        // 如果已经在处理中，则直接返回
        guard !isProcessing else { return }
        
        // 设置处理标志
        isProcessing = true
        
        // 在函数结束时重置处理标志
        defer {
            isProcessing = false
        }
        
        guard let watchURL = watchDirectory, let outputDir = outputDirectory else { return }
        let scoped = watchURL.startAccessingSecurityScopedResource()
        defer {
            if scoped {
                watchURL.stopAccessingSecurityScopedResource()
            }
        }

        let fileManager = FileManager.default
        var updatedFiles = files

        do {
            let items = try fileManager.contentsOfDirectory(at: watchURL, includingPropertiesForKeys: [.isDirectoryKey], options: [.skipsHiddenFiles])
            
            // 第一阶段：只扫描文件，不进行加密
            for item in items {
                var isDirectory: ObjCBool = false
                fileManager.fileExists(atPath: item.path, isDirectory: &isDirectory)

                if isDirectory.boolValue {
                    // 递归扫描目录中的所有文件
                    scanDirectory(item, allFiles: &updatedFiles)
                }
            }
            
            // 更新UI，显示扫描到的文件
            DispatchQueue.main.async {
                self.files = updatedFiles
            }
            
            // 第二阶段：处理许可证模板并加密文件
            for item in items {
                var isDirectory: ObjCBool = false
                fileManager.fileExists(atPath: item.path, isDirectory: &isDirectory)

                if isDirectory.boolValue {
                    var licenseID = ""
                    let folderName = item.lastPathComponent
                    
                    // 检查文件夹是否已经处理过
                    if !folderExistsInDB(path: item.path) {
                        let components = folderName.split(separator: "_")
                        let firstComponent = components.count >= 2 ? String(components[0]) : "0"
                        
                        // 检查 productID 是否为合法的数字 ID
                        let productID: String
                        if let _ = Int(firstComponent) {
                            productID = firstComponent  // 如果是数字，则使用该值
                        } else {
                            productID = "0"  // 如果不是数字，则使用默认值 0
                        }

                        // 调用添加许可证模板接口
                        let client = SOAPClient()
                        let group = DispatchGroup()
                        group.enter()
                        
                        client.addLicenseProfile(
                            endpoint: serviceURL,
                            soapAction: serviceURL + "?op=AddLicenseProfile",
                            adminemail: user?.adminemail ?? "",
                            authStr: user?.webServiceCode ?? "",
                            profileName: folderName,
                            productID: productID,
                            forceInternet: "False"
                        ) { result in
                            if let profileID = result {
                                licenseID = profileID
                                insertFolderLicenseRecord(folderName: folderName, folderPath: item.path, licenseID: profileID, productID: productID)
                                
                                // 添加权限到许可证模板
                                if let selectedRight = self.selectedRight {
                                    let rightClient = SOAPClient()
                                    
                                    rightClient.addRightToLicenseProfile(
                                        endpoint: serviceURL,
                                        soapAction: serviceURL + "?op=AddRightToLicenseProfile",
                                        adminemail: user?.adminemail ?? "",
                                        authStr: user?.webServiceCode ?? "",
                                        rightID: Int(selectedRight.id) ?? 0,
                                        licenseProfileID: Int(licenseID) ?? 0
                                    ) { result in
                                        if result == "1" {
                                            print("成功添加权限到许可证模板")
                                        } else {
                                            print("添加权限到许可证模板失败: \(result ?? "未知错误")")
                                        }
                                    }
                                }
                            }
                            group.leave()
                        }
                        
                        group.wait()
                    } else {
                        // 从数据库获取许可证ID
                        licenseID = getLicenseIDFromDB(folderPath: item.path)
                    }
                    
                    // 如果获取到许可证ID，则加密该目录下的文件
                    if !licenseID.isEmpty {
                        // 创建一个新的副本，避免并发修改
                        var localUpdatedFiles = updatedFiles
                        
                        // 按界面顺序处理文件
                        processFilesInOrder(dir: item, licenseID: licenseID, outputDir: outputDir, allFiles: &localUpdatedFiles)
                        
                        // 安全地更新文件列表
                        updatedFiles = localUpdatedFiles
                        
                        // 每处理完一个目录就更新一次UI，提高用户体验
                        DispatchQueue.main.async {
                            self.files = updatedFiles
                        }
                    }
                }
            }
        } catch {
            print("扫描目录失败: \(error)")
        }
    }

    // MARK: 扫描目录
    private func scanDirectory(_ dir: URL, allFiles: inout [FileItem]) {
        do {
            let fileURLs = try FileManager.default.contentsOfDirectory(at: dir, includingPropertiesForKeys: [.fileSizeKey, .contentModificationDateKey], options: [.skipsHiddenFiles])
            
            for url in fileURLs {
                var isDirectory: ObjCBool = false
                FileManager.default.fileExists(atPath: url.path, isDirectory: &isDirectory)
                
                if isDirectory.boolValue {
                    // 递归处理子目录
                    scanDirectory(url, allFiles: &allFiles)
                } else {
                    guard ["mp3", "mp4", "pdf"].contains(url.pathExtension.lowercased()) else { continue }
                    
                    // 检查文件是否已在数据库中存在，如果存在则跳过
                    if fileExistsInDB(filePath: url.path) {
                        continue
                    }
                    
                    // 检查文件是否稳定（完全复制完成且大小不为0）
                    if !isFileStable(url: url) {
                        continue // 跳过不稳定的文件
                    }
                    
                    // 检查文件是否已在列表中
                    if let existingIndex = allFiles.firstIndex(where: { $0.inputPath == url.path }) {
                        // 文件已存在，只有当文件状态不是已完成时才标记为待处理
                        if allFiles[existingIndex].status != .completed && !fileExistsInDB(filePath: url.path) {
                            allFiles[existingIndex].status = .pending
                        }
                    } else {
                        // 新文件，添加到列表
                        let size = (try? url.resourceValues(forKeys: [.fileSizeKey]).fileSize) ?? 0
                        let fileItem = FileItem(
                            name: url.lastPathComponent,
                            inputPath: url.path,
                            outputPath: "",
                            size: Int64(size)
                        )
                        allFiles.append(fileItem)
                    }
                }
            }
        } catch {
            print("扫描目录失败: \(error)")
        }
    }

    // MARK: 按界面顺序处理文件
    private func processFilesInOrder(dir: URL, licenseID: String, outputDir: URL, allFiles: inout [FileItem]) {
        
        // 1. 获取当前目录及其子目录下的所有待处理文件
        let pendingFiles = allFiles.filter {
            $0.status == .pending && 
            $0.inputPath.hasPrefix(dir.path)
        }
        
        // 2. 获取UI中显示的文件顺序
        let tempFiles = self.files
        var uiFileOrder: [UUID] = []
        
        // 使用主线程同步获取UI文件顺序
        DispatchQueue.main.sync {
            uiFileOrder = tempFiles.map { $0.id }
        }
        
        // 3. 按照UI显示顺序对待处理文件进行排序
        let sortedPendingFiles = pendingFiles.sorted { file1, file2 in
            let index1 = uiFileOrder.firstIndex(of: file1.id) ?? Int.max
            let index2 = uiFileOrder.firstIndex(of: file2.id) ?? Int.max
            return index1 < index2
        }
        
        // 4. 按照排序后的顺序处理文件
        for fileItem in sortedPendingFiles {
            // 检查是否应该停止加密
            if shouldStopEncryption {
                break
            }

            // 处理文件
            if let index = allFiles.firstIndex(where: { $0.id == fileItem.id }) {
                var updatedItem = allFiles[index]
                
                // 如果文件已经处理完成，跳过处理
                if updatedItem.status == .completed || fileExistsInDB(filePath: updatedItem.inputPath) {
                    continue
                }
                
                // 设置状态为处理中并更新UI
                updatedItem.status = .processing
                let fileID = updatedItem.id
                
                DispatchQueue.main.async {
                    self.currentProcessingFileID = fileID  // 设置当前处理的文件ID
                    if let uiIndex = self.files.firstIndex(where: { $0.id == fileID }) {
                        self.files[uiIndex].status = .processing
                    }
                }
                
                // 加密文件
                encryptFile(fileItem: &updatedItem, licenseID: licenseID, outputDir: outputDir)
                
                // 更新文件列表
                allFiles[index] = updatedItem
                
                // 更新UI
                let finalStatus = updatedItem.status
                let outputPath = updatedItem.outputPath
                let errorMessage = updatedItem.errorMessage
                
                DispatchQueue.main.async {
                    if let uiIndex = self.files.firstIndex(where: { $0.id == fileID }) {
                        self.files[uiIndex].status = finalStatus
                        self.files[uiIndex].outputPath = outputPath
                        self.files[uiIndex].errorMessage = errorMessage
                    }
                }
            }
        }
        
        // 5. 最后再次更新UI，确保所有文件状态和输出路径都正确显示
        // 创建一个副本，避免在闭包中捕获inout参数
        let finalAllFiles = allFiles
        
        // 使用主线程同步更新UI，确保更新完成后再继续执行
        DispatchQueue.main.sync {
            for file in finalAllFiles {
                if let uiIndex = self.files.firstIndex(where: { $0.id == file.id }) {
                    if self.files[uiIndex].status != .completed {
                        // 只有当文件状态为已完成时才更新输出路径
                        if file.status == .completed {
                            self.files[uiIndex].outputPath = file.outputPath
                        }
                        self.files[uiIndex].status = file.status
                        self.files[uiIndex].errorMessage = file.errorMessage
                    }
                }
            }
        }
    }

    // MARK: 加密待处理文件
    private func encryptPendingFiles(dir: URL, licenseID: String, outputDir: URL, allFiles: inout [FileItem]) {
        // 创建一个副本，用于按照界面显示顺序处理文件
        let filesToProcess = allFiles.filter { $0.status == .pending }
        
        // 按照界面显示顺序处理文件
        for i in 0..<filesToProcess.count {
            // 检查是否应该停止加密
            if shouldStopEncryption {
                break
            }

            let fileItem = filesToProcess[i]
            
            // 查找文件在allFiles中的索引
            if let index = allFiles.firstIndex(where: { $0.id == fileItem.id }) {
                // 如果文件已经处理完成，跳过处理
                if allFiles[index].status == .completed || fileExistsInDB(filePath: fileItem.inputPath) {
                    continue
                }
                // 设置状态为"处理中"并立即更新UI
                var updatedItem = allFiles[index]
                updatedItem.status = .processing
                let fileID = updatedItem.id
                
                DispatchQueue.main.async {
                    if let uiIndex = self.files.firstIndex(where: { $0.id == fileID }) {
                        self.files[uiIndex].status = .processing
                    }
                }
                
                // 加密文件
                encryptFile(fileItem: &updatedItem, licenseID: licenseID, outputDir: outputDir)
                
                // 更新文件列表中的文件状态
                allFiles[index] = updatedItem
                
                // 立即更新UI
                let finalStatus = updatedItem.status
                let outputPath = updatedItem.outputPath
                let errorMessage = updatedItem.errorMessage
                
                DispatchQueue.main.async {
                    if let uiIndex = self.files.firstIndex(where: { $0.id == fileID }) {
                        self.files[uiIndex].status = finalStatus
                        self.files[uiIndex].outputPath = outputPath
                        self.files[uiIndex].errorMessage = errorMessage
                    }
                }
            }
        }
        
        // 递归处理子目录（保留原有功能）
        do {
            let fileURLs = try FileManager.default.contentsOfDirectory(at: dir, includingPropertiesForKeys: [.fileSizeKey], options: [.skipsHiddenFiles])
            
            for url in fileURLs {
                var isDirectory: ObjCBool = false
                FileManager.default.fileExists(atPath: url.path, isDirectory: &isDirectory)
                
                if isDirectory.boolValue {
                    // 递归处理子目录
                    encryptPendingFiles(dir: url, licenseID: licenseID, outputDir: outputDir, allFiles: &allFiles)
                }
            }
        } catch {
            print("扫描目录失败: \(error)")
        }
    }
    
    // MARK: 加密文件
    private func encryptFile(fileItem: inout FileItem, licenseID: String, outputDir: URL) {
    
        // 确保输出目录有访问权限
        let outputScoped = outputDirectory?.startAccessingSecurityScopedResource() ?? false
        defer {
            if outputScoped {
                outputDirectory?.stopAccessingSecurityScopedResource()
            }
        }
        
        let inputURL = URL(fileURLWithPath: fileItem.inputPath)
        
        // 计算相对路径，保留目录结构
        let relativePath = inputURL.path.replacingOccurrences(of: watchDirectory?.path ?? "", with: "")
        let relativeURL = URL(fileURLWithPath: relativePath)
        let relativeDir = relativeURL.deletingLastPathComponent().path
        
        // 获取顶层文件夹名称（第一级目录）
        var pathComponents = relativeDir.split(separator: "/").map(String.init)
        let topLevelFolderName = pathComponents.isEmpty ? "" : pathComponents[0]
        
        // 创建新的顶层文件夹名称：许可证模板ID_原文件夹名
        let newTopLevelFolderName = "\(licenseID)_\(topLevelFolderName)"
        
        // 构建新的相对路径，只替换顶层文件夹名称
        if !pathComponents.isEmpty {
            pathComponents[0] = newTopLevelFolderName
            let newRelativeDir = "/" + pathComponents.joined(separator: "/")
            
            // 创建输出目录
            let outputFolder = outputDir.appendingPathComponent(newRelativeDir)
            do {
                try FileManager.default.createDirectory(at: outputFolder, withIntermediateDirectories: true, attributes: nil)
            } catch {
                print("创建输出目录失败: \(error.localizedDescription)")
                fileItem.status = .failed
                fileItem.errorMessage = "创建目录失败: \(error.localizedDescription)"
                return
            }
            
            // 构造输出文件名（加 _P 后缀）
            let fileName = inputURL.deletingPathExtension().lastPathComponent + "_P"
            let fileExtension = inputURL.pathExtension
            let outputFileName = fileName + "." + fileExtension
            let outputPath = outputFolder.appendingPathComponent(outputFileName).path
            
            // 设置输出路径
            fileItem.outputPath = outputPath
        } else {
            // 如果没有相对路径（文件直接在监视目录下），则直接在输出目录创建文件
            let outputFolder = outputDir.appendingPathComponent("\(licenseID)_files")
            do {
                try FileManager.default.createDirectory(at: outputFolder, withIntermediateDirectories: true, attributes: nil)
            } catch {
                print("创建输出目录失败: \(error.localizedDescription)")
                fileItem.status = .failed
                fileItem.errorMessage = "创建目录失败: \(error.localizedDescription)"
                return
            }
            
            // 构造输出文件名（加 _P 后缀）
            let fileName = inputURL.deletingPathExtension().lastPathComponent + "_P"
            let fileExtension = inputURL.pathExtension
            let outputFileName = fileName + "." + fileExtension
            let outputPath = outputFolder.appendingPathComponent(outputFileName).path
            
            // 设置输出路径
            fileItem.outputPath = outputPath
        }
        
        // 获取加密工具路径
        guard let mp4encryptPath = Bundle.main.resourceURL?.appendingPathComponent("mp4encrypt").path else {
            fileItem.status = .failed
            fileItem.errorMessage = "无法找到 mp4encrypt 可执行文件"
            return
        }
        
        // MARK: 设置加密命令参数
        let domain = user?.isChineseVersion ?? false ? "CN" : "COM"
        let adminEmail = user?.adminemail ?? ""
        let authStr = user?.webServiceCode ?? ""
        
        let command = [
            mp4encryptPath,
            "-ServerDomain", domain,
            "-AdminEmail", adminEmail,
            "-WebServiceAuthStr", authStr,
            "-ID", licenseID,
            "-Input", fileItem.inputPath,
            "-Output", fileItem.outputPath
        ]
        
        // MARK: 执行加密命令
        let process = Process()
        process.executableURL = URL(fileURLWithPath: command[0])
        process.arguments = Array(command.dropFirst())
        
        let pipe = Pipe()
        process.standardError = pipe
        process.standardOutput = pipe
        
        do {
            try process.run()
            process.waitUntilExit()
            
            // 在加密成功后更新UI
            if process.terminationStatus == 0 {
                fileItem.status = .completed
                
                var licenseProfileName = ""
                
                // 从数据库获取许可证模板名称
                var db: OpaquePointer?
                if sqlite3_open(databasePath, &db) == SQLITE_OK {
                    let query = "SELECT folder_name FROM Folder_License_Map WHERE license_id = ? LIMIT 1"
                    var stmt: OpaquePointer?
                    
                    if sqlite3_prepare_v2(db, query, -1, &stmt, nil) == SQLITE_OK {
                        sqlite3_bind_text(stmt, 1, (licenseID as NSString).utf8String, -1, nil)
                        
                        if sqlite3_step(stmt) == SQLITE_ROW {
                            if let cString = sqlite3_column_text(stmt, 0) {
                                licenseProfileName = String(cString: cString)
                            }
                        }
                        sqlite3_finalize(stmt)
                    }
                    sqlite3_close(db)
                }
                
                // 加密成功后，将记录添加到数据库
                // 只有当文件不存在于数据库中时才插入记录
                if !fileExistsInDB(filePath: fileItem.inputPath) {
                    insertFileProcessRecord(
                        fileName: fileItem.name,
                        filePath: fileItem.inputPath,
                        profileID: licenseID,
                        licenseProfile: licenseProfileName
                    )
                }

            } else {
                let errorData = pipe.fileHandleForReading.readDataToEndOfFile()
                let errorMessage = String(data: errorData, encoding: .utf8) ?? "未知错误"
                fileItem.status = .failed
                fileItem.errorMessage = errorMessage

                print("加密失败: \(errorMessage)")
            }
        } catch {
            fileItem.status = .failed
            fileItem.errorMessage = error.localizedDescription
            
            print("加密失败: \(error.localizedDescription)")
        }
    }
    
    // MARK: 从数据库获取许可证ID
    private func getLicenseIDFromDB(folderPath: String) -> String {
        var db: OpaquePointer?
        var licenseID = ""
        
        if sqlite3_open(databasePath, &db) == SQLITE_OK {
            let query = "SELECT license_id FROM Folder_License_Map WHERE folder_path = ? LIMIT 1"
            var stmt: OpaquePointer?
            
            if sqlite3_prepare_v2(db, query, -1, &stmt, nil) == SQLITE_OK {
                sqlite3_bind_text(stmt, 1, (folderPath as NSString).utf8String, -1, nil)
                
                if sqlite3_step(stmt) == SQLITE_ROW {
                    if let cString = sqlite3_column_text(stmt, 0) {
                        licenseID = String(cString: cString)
                    }
                }
                sqlite3_finalize(stmt)
            }
            sqlite3_close(db)
        }
        
        return licenseID
    }

    // MARK: 创建数据库
    private func createLogDatabaseIfNeeded() {
        var db: OpaquePointer?
        if sqlite3_open(databasePath, &db) == SQLITE_OK {
            // 保留原有的 Folder_License_Map 表
            let createFolderTableQuery = """
                CREATE TABLE IF NOT EXISTS Folder_License_Map (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    folder_name TEXT,
                    folder_path TEXT,
                    license_id TEXT,
                    license_name TEXT,
                    product_id TEXT
                );
            """
            
            // 添加新的 File_Process_Details 表
            let createFileTableQuery = """
                CREATE TABLE IF NOT EXISTS File_Process_Details (
                    file_id INTEGER PRIMARY KEY AUTOINCREMENT,
                    file_name TEXT NOT NULL,
                    file_path TEXT NOT NULL UNIQUE,
                    profile_id TEXT NOT NULL,
                    license_profile TEXT NOT NULL,
                    process_time TEXT NOT NULL
                );
            """
            
            // 创建 Folder_License_Map 表
            if sqlite3_exec(db, createFolderTableQuery, nil, nil, nil) != SQLITE_OK {
                print("❌ 创建文件夹许可证映射表失败")
            } else {
                print("✅ 文件夹许可证映射表准备就绪")
            }
            
            // 创建 File_Process_Details 表
            if sqlite3_exec(db, createFileTableQuery, nil, nil, nil) != SQLITE_OK {
                print("❌ 创建文件处理记录表失败")
            } else {
                print("✅ 文件处理记录表准备就绪")
            }
            
            sqlite3_close(db)
        } else {
            print("❌ 无法打开数据库")
        }
    }
    
    // MARK: 检测文件夹（许可证模板）是否存在
    private func folderExistsInDB(path: String) -> Bool {
        var db: OpaquePointer?
        var exists = false
        if sqlite3_open(databasePath, &db) == SQLITE_OK {
            let query = "SELECT 1 FROM Folder_License_Map WHERE folder_path = ? LIMIT 1"
            var stmt: OpaquePointer?
            if sqlite3_prepare_v2(db, query, -1, &stmt, nil) == SQLITE_OK {
                sqlite3_bind_text(stmt, 1, (path as NSString).utf8String, -1, nil)
                if sqlite3_step(stmt) == SQLITE_ROW {
                    exists = true
                }
                sqlite3_finalize(stmt)
            }
            sqlite3_close(db)
        }
        return exists
    }
    
    // MARK: 插入许可证模板和文件夹记录到数据库
    private func insertFolderLicenseRecord(folderName: String, folderPath: String, licenseID: String, productID: String) {
        var db: OpaquePointer?
        if sqlite3_open(databasePath, &db) == SQLITE_OK {
            let insertQuery = "INSERT INTO Folder_License_Map (folder_name, folder_path, license_id, license_name, product_id) VALUES (?, ?, ?, ?, ?)"
            var stmt: OpaquePointer?
            if sqlite3_prepare_v2(db, insertQuery, -1, &stmt, nil) == SQLITE_OK {
                sqlite3_bind_text(stmt, 1, (folderName as NSString).utf8String, -1, nil)
                sqlite3_bind_text(stmt, 2, (folderPath as NSString).utf8String, -1, nil)
                sqlite3_bind_text(stmt, 3, (licenseID as NSString).utf8String, -1, nil)
                sqlite3_bind_text(stmt, 4, (folderName as NSString).utf8String, -1, nil)
                sqlite3_bind_text(stmt, 5, (productID as NSString).utf8String, -1, nil)
                if sqlite3_step(stmt) == SQLITE_DONE {
                    print("✅ 插入记录成功")
                } else {
                    print("❌ 插入记录失败")
                }
                sqlite3_finalize(stmt)
            } else {
                print("❌ 预处理失败")
            }
            sqlite3_close(db)
        } else {
            print("❌ 无法打开数据库")
        }
    }
    
    // MARK: 检查文件是否已在数据库中存在
    private func fileExistsInDB(filePath: String) -> Bool {
        var db: OpaquePointer?
        var exists = false
        
        if sqlite3_open(databasePath, &db) == SQLITE_OK {
            let queryString = "SELECT COUNT(*) FROM File_Process_Details WHERE file_path = ?;"
            var queryStatement: OpaquePointer?
            
            if sqlite3_prepare_v2(db, queryString, -1, &queryStatement, nil) == SQLITE_OK {
                sqlite3_bind_text(queryStatement, 1, (filePath as NSString).utf8String, -1, nil)
                
                if sqlite3_step(queryStatement) == SQLITE_ROW {
                    let count = sqlite3_column_int(queryStatement, 0)
                    exists = (count > 0)
                }
            }
            
            sqlite3_finalize(queryStatement)
            sqlite3_close(db)
        }
        
        return exists
    }
    
    // MARK: 将文件加密记录插入数据库
    private func insertFileProcessRecord(fileName: String, filePath: String, profileID: String, licenseProfile: String) {
        var db: OpaquePointer?
        
        if sqlite3_open(databasePath, &db) == SQLITE_OK {
            let insertString = """
            INSERT INTO File_Process_Details (file_name, file_path, profile_id, license_profile, process_time)
            VALUES (?, ?, ?, ?, datetime('now', 'localtime'));
            """
            
            var insertStatement: OpaquePointer?
            
            if sqlite3_prepare_v2(db, insertString, -1, &insertStatement, nil) == SQLITE_OK {
                sqlite3_bind_text(insertStatement, 1, (fileName as NSString).utf8String, -1, nil)
                sqlite3_bind_text(insertStatement, 2, (filePath as NSString).utf8String, -1, nil)
                sqlite3_bind_text(insertStatement, 3, (profileID as NSString).utf8String, -1, nil)
                sqlite3_bind_text(insertStatement, 4, (licenseProfile as NSString).utf8String, -1, nil)
                
                if sqlite3_step(insertStatement) == SQLITE_DONE {
                    print("✅ 文件处理记录添加成功: \(fileName)")
                } else {
                    let errorMessage = String(cString: sqlite3_errmsg(db))
                    print("❌ 添加文件处理记录失败: \(fileName), 错误: \(errorMessage)")
                }
            }
            
            sqlite3_finalize(insertStatement)
            sqlite3_close(db)
        }
    }

    // MARK: 添加新方法：检查文件是否稳定（完全复制完成）
    private func isFileStable(url: URL) -> Bool {
        let path = url.path
        let now = Date()
        
        do {
            // 获取当前文件大小和修改时间
            let resourceValues = try url.resourceValues(forKeys: [.fileSizeKey, .contentModificationDateKey])
            let currentSize = Int64(resourceValues.fileSize ?? 0)
            _ = resourceValues.contentModificationDate ?? now
            
            // 如果文件大小为0，则认为文件不稳定（正在创建或复制中）
            if currentSize == 0 {
                return false
            }
            
            // 检查文件是否可以打开进行读取（如果文件正在被写入，可能会失败）
            if let fileHandle = try? FileHandle(forReadingFrom: url) {
                // 文件可以打开进行读取
                defer {
                    try? fileHandle.close()
                }
                
                // 检查文件是否在我们的稳定性映射中
                if let previousCheck = fileStabilityMap[path] {
                    // 如果文件大小在一段时间内没有变化，并且修改时间没有更新，则认为文件稳定
                    let sizeStable = previousCheck.size == currentSize
                    let timeElapsed = now.timeIntervalSince(previousCheck.timestamp) >= 2.0 // 至少2秒没有变化
                    
                    if sizeStable && timeElapsed {
                        // 文件稳定，从映射中移除
                        fileStabilityMap.removeValue(forKey: path)
                        return true
                    } else {
                        // 文件仍在变化，更新检查信息
                        fileStabilityMap[path] = (currentSize, now)
                        return false
                    }
                } else {
                    // 首次检查到此文件，添加到映射中
                    fileStabilityMap[path] = (currentSize, now)
                    return false
                }
            } else {
                // 文件无法打开进行读取，可能正在被写入
                return false
            }
        } catch {
            print("检查文件稳定性失败: \(error)")
            return false
        }
    }

    // MARK: 设置状态颜色
    private func statusColor(for status: FileStatus) -> Color {
        switch status {
        case .pending: return .primary
        case .processing: return .blue
        case .completed: return .green
        case .failed: return .red
        }
    }

    // MARK: 打开文件夹并选中文件
    private func openFolder(url: URL?) {
        guard let url = url else { return }
        
        // 获取文件路径和文件夹路径
        let filePath = url.path
        let folderPath = url.deletingLastPathComponent().path
        
        // 使用NSWorkspace的selectFile方法打开文件夹并选中文件
        NSWorkspace.shared.selectFile(filePath, inFileViewerRootedAtPath: folderPath)
    }
    
    // MARK: 打开文件
    private func openFile(url: URL?) {
        guard let url = url else { return }
        NSWorkspace.shared.open(url)
    }
}
